package com.itbac.j2cache.aop.generator;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;

/**
* @description key 生成策略 ：缓存名 + 缓存key ,支持Spring el表达式
* 用于自定义缓存注解：
* com.itbac.j2cache.aop.annotatin.J2Cacheable
* com.itbac.j2cache.aop.annotatin.J2CacheEvict
* com.itbac.j2cache.aop.annotatin.J2CachePut
*
* @author itbac
* @email 1218585258@qq.com
* @date 2020/6/17
*/
@Component
public class DefaultKeyGenerator {
   private static Logger logger = LoggerFactory.getLogger(DefaultKeyGenerator.class);

   //SpEL 解析器
   private SpelExpressionParser parser = new SpelExpressionParser();
   //用于获取方法参数定义名字
   private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();

   public String generateKey(ProceedingJoinPoint pjp,String cacheName,String cacheKey) throws NoSuchMethodException {
       if (StringUtils.isEmpty(cacheKey)) {
           throw new NullPointerException("cacheKey 不能为空");
       }
       Signature signature = pjp.getSignature();
       if (StringUtils.isEmpty(cacheName)) {
           cacheName = signature.getDeclaringTypeName() + "." + signature.getName();
       }
       EvaluationContext evaluationContext = new StandardEvaluationContext();
       if (!(signature instanceof MethodSignature)) {
           throw new NullPointerException("这个注解只能用在方法上");
       }
       MethodSignature methodSignature = (MethodSignature) signature;
       Method method = pjp.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getMethod().getParameterTypes());
       String[] parameterNames = nameDiscoverer.getParameterNames(method);
       if (null == parameterNames) {
           throw new NullPointerException("当前方法没有参数,无法通过spring EL 表达式获取key");
       }
       Object[] args = pjp.getArgs();
       for (int i = 0; i < parameterNames.length; i++) {
           evaluationContext.setVariable(parameterNames[i], args[i]);
       }
       String result = "CacheName_" + cacheName + "_CacheKey_" +
               parser.parseExpression(cacheKey).getValue(evaluationContext, String.class);
       logger.info(">>>>>>>>>>  DefaultKeyGenerator  key ： {}  <<<<<<<<<<", result);
       return result;
   }


}
